package orbitorcensor;

import java.util.ArrayList;
import java.util.List;

import sprinter.ISprinter;
import sprinter.ISprinter.GraphType;
import jsprintorbitor.bridge2native.BridgeUtils;
import jsprintorbitor.experiment.SpOrbExperimentContext;
import jsprintorbitor.experiment.SpOrbExperimentSettings;
import jsprintorbitor.experiment.graph.AlgGenPair;
import jsprintorbitor.experiment.graph.IGraphAlgorithm;
import jsprintorbitor.experiment.graph.IGraphGenerator;
import laboratoryQ.experiment.IExperiment;
import laboratoryQ.experiment.IExperimentResult;
import laboratoryQ.junit.ignore.patch.BaseTestCase;

public class TestExperimentRun extends BaseTestCase {
	static {
		TestObjectsLifetime.init();
	}

	public void testExperimentRun() {
		SpOrbExperimentSettings settings = new SpOrbExperimentSettings();
		settings.initialise();
		settings.randomSeed = 0;
		fillGraphTraversal(settings);
		fillShortestPath(settings);
		fillMaxFlow(settings);
		fillMinCostFlow(settings);
		settings.validate();
		SpOrbExperimentContext ctx = (SpOrbExperimentContext) settings
			.getExperimentContextFactory().newContext(settings);
		IExperimentResult experimentResult = settings.getExperiment().runExperiment(ctx, new IExperiment.NOPExpRunStatusHandler());
		assertNotNull(experimentResult);
	}

	private static void fillGraphTraversal(SpOrbExperimentSettings settings) {
		settings.gtrvexSzRngEnabled = true;
		settings.gtrvexSzRngVrtCntBeg = 20;
		settings.gtrvexSzRngVrtCntEnd = 25;
		settings.gtrvexSzRngExpRunCnt = 5;
		settings.gtrvexSzRngV2EPower = 1.8;
		settings.gtrvexSzRngV2EMul = 2.5;
		settings.gtrvexSzRngV2EAdd = 30;

		settings.gtrvexPwRngEnabled = true;
		settings.gtrvexPwRngVrtCnt = 20;
		settings.gtrvexPwRngExpRunCnt = 5;
		settings.gtrvexPwRngBeg = 1.3;
		settings.gtrvexPwRngEnd = 2.1;
		settings.gtrvexPwRngStep = 0.1;
		settings.gtrvexPwRngMul = 2.5;
		settings.gtrvexPwRngAdd = 30;

		AlgGenPair[][] travExperimentCases = genTravExperimentCases();
		settings.traversalExperimentCases = travExperimentCases[0];
		settings.traversalExperimentCasesVirtual = travExperimentCases[1];
	}

	private static void fillShortestPath(SpOrbExperimentSettings settings) {
		settings.dejkstraPwRngEnabled = true;
		settings.dejkstraPwRngVrtCnt = 20;
		settings.dejkstraPwRngExpRunCnt = 5;
		settings.dejkstraPwRngBeg = 1.3;
		settings.dejkstraPwRngEnd = 2.1;
		settings.dejkstraPwRngStep = 0.1;
		settings.dejkstraPwRngMul = 2.5;
		settings.dejkstraPwRngAdd = 30;

		settings.shortestPathExperimentCases = genShortestPathExperimentCases();
	}

	private static void fillMaxFlow(SpOrbExperimentSettings settings) {
		settings.dinicPwRngEnabled = true;
		settings.dinicPwRngVrtCnt = 20;
		settings.dinicPwRngExpRunCnt = 5;
		settings.dinicPwRngBeg = 1.3;
		settings.dinicPwRngEnd = 2.1;
		settings.dinicPwRngStep = 0.1;
		settings.dinicPwRngMul = 2.5;
		settings.dinicPwRngAdd = 30;

		settings.maxFlowExperimentCases = genMaxFlowExperimentCases();
	}

	private static void fillMinCostFlow(SpOrbExperimentSettings settings) {
		settings.mcfPwRngEnabled = true;
		settings.mcfPwRngVrtCnt = 80;
		settings.mcfPwRngExpRunCnt = 30;
		settings.mcfPwRngBeg = 1.3;
		settings.mcfPwRngEnd = 1.8;
		settings.mcfPwRngStep = 0.01;
		settings.mcfPwRngMul = 2.5;
		settings.mcfPwRngAdd = 30;
		
		settings.minCostFlowExperimentCases = genMinCostFlowExperimentCases();
	}

	private static AlgGenPair[][] genTravExperimentCases() {
		List<AlgGenPair> experimentCases = new ArrayList<AlgGenPair>();
		List<AlgGenPair> experimentCasesVirtual = new ArrayList<AlgGenPair>();
		ISprinter[] allSprinters = BridgeUtils.getAllSprinters();
		int n = allSprinters.length;
		for (int i = 0; i < n; i++) {
			ISprinter sprinter = allSprinters[i];
			if (
					sprinter.getExperimentLabels().contains("graph-impl-compare") ||
					sprinter.getExperimentLabels().contains("CURRENT")
			) {
				IGraphAlgorithm algorithm = sprinter.newBFSGraphTraversalAlgorithm();
				IGraphGenerator vectorGraphGen = sprinter.newEasyRandomGraphGenerator(GraphType.VECTOR);
				experimentCases.add(new AlgGenPair(
						algorithm,
						vectorGraphGen,
						i, 0
				));
				IGraphGenerator matrixGraphGen = sprinter.newEasyRandomGraphGenerator(GraphType.MATRIX);
				experimentCases.add(new AlgGenPair(
						algorithm,
						matrixGraphGen,
						i, 1
				));
				IGraphGenerator igraphGen = sprinter.newEasyRandomGraphGenerator(GraphType.IGRAPH);
				experimentCasesVirtual.add(new AlgGenPair(
						algorithm,
						igraphGen,
						i, 2
				));
				IGraphGenerator nonstructedGen = sprinter.newEasyRandomGraphGenerator(GraphType.COMPACT_NOTSTRUCTED);
				experimentCases.add(new AlgGenPair(
						algorithm,
						nonstructedGen,
						i, 3
				));
			}
		}
		return new AlgGenPair[][] {
				experimentCases.toArray(new AlgGenPair[experimentCases.size()]),
				experimentCasesVirtual.toArray(new AlgGenPair[experimentCasesVirtual.size()]),
			};
	}

	private static AlgGenPair[] genShortestPathExperimentCases() {
		List<AlgGenPair> experimentCases = new ArrayList<AlgGenPair>();
		ISprinter[] allSprinters = BridgeUtils.getAllSprinters();
		int n = allSprinters.length;
		for (int i = 0; i < n; i++) {
			ISprinter sprinter = allSprinters[i];
			IGraphAlgorithm algorithm = sprinter.newDejkstraAlgorithm(0);
			experimentCases.add(new AlgGenPair(
					algorithm,
					sprinter.newEasyRandomGraphGenerator(GraphType.VECTOR),
					i, 0
			));
//			experimentCases.add(new AlgGenPair(
//					algorithm,
//					sprinter.newEasyRandomGraphGenerator(GraphType.MATRIX)
//			));
		}
		return experimentCases.toArray(new AlgGenPair[experimentCases.size()]);
	}

	private static AlgGenPair[] genMaxFlowExperimentCases() {
		List<AlgGenPair> experimentCases = new ArrayList<AlgGenPair>();
		ISprinter[] allSprinters = BridgeUtils.getAllSprinters();
		int n = allSprinters.length;
		for (int i = 0; i < n; i++) {
			ISprinter sprinter = allSprinters[i];
			IGraphAlgorithm algorithm = sprinter.newDinicAlgorithm(0, 1);
			experimentCases.add(new AlgGenPair(
					algorithm,
					sprinter.newFlowGraphGenerator(GraphType.VECTOR),
					i, 0
			));
//			experimentCases.add(new AlgGenPair(
//					algorithm,
//					sprinter.newEasyRandomGraphGenerator(GraphType.MATRIX)
//			));
		}
		return experimentCases.toArray(new AlgGenPair[experimentCases.size()]);
	}

	// TODO: fix: update from Main
	private static AlgGenPair[] genMinCostFlowExperimentCases() {
		List<AlgGenPair> experimentCases = new ArrayList<AlgGenPair>();
		ISprinter[] allSprinters = BridgeUtils.getAllSprinters();
		int n = allSprinters.length;
		for (int i = 0; i < n; i++) {
			ISprinter sprinter = allSprinters[i];
			if (
					sprinter.getExperimentLabels().contains("min-cost-flow-experiment") ||
					sprinter.getExperimentLabels().contains("CURRENT")
			) {
				IGraphAlgorithm algorithm = sprinter.newMinCostFlowAlgorithm(0, 1);
				experimentCases.add(new AlgGenPair(
						algorithm,
						sprinter.newCostFlowGraphGenerator(GraphType.VECTOR),
						i, 0
				));
			}
		}
		return experimentCases.toArray(new AlgGenPair[experimentCases.size()]);
	}

	public void testChainAlgorithm() {
		native_testChainAlgorithm();
	}

	private native void native_testChainAlgorithm();
}
